package com.unitd.base.module.master.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.unitd.base.frame.plugin.module.dto.ResponseUtils;
import com.unitd.base.frame.util.BeanUtils;
import com.unitd.base.frame.util.DateUtils;
import com.unitd.base.frame.util.StringUtils;
import com.unitd.base.module.comm.enums.DeleteFlagEnum;
import com.unitd.base.module.comm.enums.StatusEnum;
import com.unitd.base.module.comm.exception.RRException;
import com.unitd.base.module.comm.utils.CharUtil;
import com.unitd.base.module.comm.utils.Constant;
import com.unitd.base.module.comm.web.validator.Assert;
import com.unitd.base.module.consumer.comm.util.ApiUserUtils;
import com.unitd.base.module.consumer.comm.util.CommonUtil;
import com.unitd.base.module.consumer.pojo.wechat.WechatData;
import com.unitd.base.module.consumer.pojo.wechat.WechatUser;
import com.unitd.base.module.master.mybatis.mapper.UserMapper;
import com.unitd.base.module.master.pojo.dto.DatasourceBaseVO;
import com.unitd.base.module.master.pojo.po.UserPO;
import com.unitd.base.module.master.service.DatasourceBaseService;
import com.unitd.base.module.master.service.TokenService;
import com.unitd.base.module.master.service.UserAuthService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.Map;

/**
 * 用户登录、授权信息业务逻辑类
 *
 * @author hudan
 * @version 1.0
 * @filename UserAuthServiceImpl.java
 * @copyright www.pactera.com
 * @date 2020-08-09
 */
@Slf4j
@Service
public class UserAuthServiceImpl extends ServiceImpl<UserMapper, UserPO> implements UserAuthService {

    @Autowired
    private DatasourceBaseService datasourceBaseService;
    @Autowired
    private TokenService tokenService;

    /**
     * 处理用户登录
     *
     * @param mobile   登录手机号码
     * @param password 登录密码
     * @return 登录结果
     */
    @Override
    @Transactional
    public Map<String, Object> login(String mobile, String password) {

        // 用户登录
        UserPO user = baseMapper.selectByMobile(mobile);
        Assert.isNull(user, "手机号或密码错误");

        // 密码错误
        if (!user.getPassword().equals(DigestUtils.sha256Hex(password))) {
            throw new RRException("手机号或密码错误");
        }

        // 生成token
        Map<String, Object> map = tokenService.createToken(user.getId());
        return ResponseUtils.toResponsSuccess(map);
    }

    /**
     * 微信登录
     *
     * @param jsonParam 登录请求参数
     * @param clientIp  发起登录客户端ip
     * @return 登录结果
     */
    @Override
    @Transactional
    public Map<String, Object> loginBywx(JSONObject jsonParam, String clientIp) {
        String code = jsonParam.getString("code");

        /* 得到请求中的微信用户信息 */
        WechatData wechatData = null;
        if (null != jsonParam.get("userInfo")) {
            wechatData = jsonParam.getObject("userInfo", WechatData.class);
        }
        if (BeanUtils.isNull(wechatData)) {
            return ResponseUtils.toResponsFail("登录失败");
        }
        WechatUser wechatUser = wechatData.getUserInfo();

        /* 获取openid, 通过自定义工具类组合出小程序需要的登录凭证 code */
        String requestUrl = ApiUserUtils.getWebAccess(code);
        log.info("》》》组合token为：" + requestUrl);
        JSONObject sessionData = CommonUtil.httpsRequest(requestUrl, "GET", null);
        if (BeanUtils.isNull(sessionData)) {
            return ResponseUtils.toResponsFail("登录失败");
        }

        // 得到当前登录用户的与微信绑定的openid
        String openid = sessionData.getString("openid");
        if (StringUtils.isNull(openid)) {
            return ResponseUtils.toResponsFail("登录失败");
        }

        // 验证用户信息完整性
        String sha1 = CommonUtil.getSha1(wechatData.getRawData() + sessionData.getString("session_key"));
        if (!wechatData.getSignature().equals(sha1)) {
            return ResponseUtils.toResponsFail("登录失败");
        }

        Date nowTime = new Date();

        // 根据微信的openid判断是否存在该用户,如果不存在则直接新增
        UserPO user = baseMapper.selectByWxOpenId(openid);
        if (BeanUtils.isNull(user)) {
            user = new UserPO();
            user.setUserName("微信用户" + CharUtil.getRandomString(12));
            user.setNickName(wechatUser.getNickName());
            user.setPassword(openid);
            // 用户性别(0:未知,1:男,2:女)
            user.setGender(wechatUser.getGender());
            // 用户头像
            user.setAvatar(wechatUser.getAvatarUrl());
            // 绑定的微信的openid
            user.setWxOpenId(openid);
            // TableField
            user.setRegisterIp(clientIp);
            // 用户注册时间
            user.setRegisterTime(nowTime);
            // 最后登录IP
            user.setLastLoginIp(user.getRegisterIp());
            // 最后登录时间
            user.setLastLoginTime(user.getRegisterTime());
            //生效状态
            user.setStatus(StatusEnum.ONE.getCode());
            //是否已删除
            user.setDeleteFlag(DeleteFlagEnum.NO.getCode());
            //创建时间
            user.setCreateTime(DateUtils.getCurrDate(DateUtils.TIMESTAMP_PATTERN));
            //更新时间
            user.setUpdateTime(DateUtils.getCurrDate(DateUtils.TIMESTAMP_PATTERN));

            baseMapper.insert(user);
        } else {
            // 最后登录IP
            user.setLastLoginIp(clientIp);
            // 最后登录时间
            user.setLastLoginTime(nowTime);
            baseMapper.updateById(user);
        }

        // 创建当前登录用户的访问 Token
        Map<String, Object> tokenMap = tokenService.createToken(user.getId());
        String token = MapUtils.getString(tokenMap, Constant.TOKEN_NAME);

        if (BeanUtils.isNull(wechatUser) || StringUtils.isNull(token)) {
            return ResponseUtils.toResponsFail("登录失败");
        }

        // 得到当前登录用户的默认数据源
        DatasourceBaseVO datasource = datasourceBaseService.getById(user.getDefDbId());

        Map<String, Object> resultObj = Maps.newHashMap();
        resultObj.put("token", token);
        resultObj.put("userInfo", user);
        resultObj.put("userId", user.getId());
        resultObj.put("datasource", datasource);
        return ResponseUtils.toResponsSuccess(resultObj);
    }
}